home *** CD-ROM | disk | FTP | other *** search
/ Assassins - Ultimate CD Games Collection 2 / Assassins 2 - Ultimate Games No. 2 (1995)(Weird Science)[!][Amiga-CD32-CDTV].iso / disks / mv-9.dms / mv-9.adf / GiffToIff / giftrans / Giftrans.Src / source / giftrans.orig < prev    next >
Text File  |  1995-03-20  |  24KB  |  871 lines

  1. /*
  2. ** GIFtrans v1.11.1
  3. **
  4. ** Convert any GIF file into a GIF89a
  5. ** Allows for setting the transparent or background color, changing colors,
  6. ** adding or removing comments. Also code to analyze GIF contents.
  7. **
  8. ** Copyright (c) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de>
  9. **
  10. ** Permission to use, copy, modify, and distribute this software for any
  11. ** purpose and without fee is hereby granted, provided that the above
  12. ** copyright notice appears in all copies. This software is provided "as is"
  13. ** and without any express or implied warranties.
  14. **
  15. ** This program has been tested on a HP9000/720 with HP-UX A.08.07
  16. ** In this environment, neither lint -u nor gcc -Wall produce any messages.
  17. ** If you encounter any errors or need to make any changes to port it
  18. ** to another platform, please contact me.
  19. **
  20. ** Known bugs:
  21. **    -B flag won't work if there's an Extension between the Global Color
  22. **    Table and the Image Descriptor (or Graphic Control Extension). If -V
  23. **    has been specified, a Warning Message will be displayed.
  24. **    Will be fixed in 2.0
  25. **    Always outputs GIF89a. Shouldn't do this if version is newer.
  26. **    -D option may output changed data instead of original data, use
  27. **    with caution, best only with then -L option.
  28. **
  29. ** Version history
  30. **
  31. ** Version 1.11.1 - 11.8.94
  32. **    Allows for use of the -g option without the -B option.
  33. **
  34. ** Version 1.11 - 21.7.94
  35. **    Moved Plain Text Extension to the Extensions section where it belongs.
  36. **    Accept Unknown Extension Labels.
  37. **    Incorporated MS-DOS port by enzo@hk.net (Enzo Michelangeli).
  38. **    Added -o and -e options to redirect stdout and stderr.
  39. **    Added -D debug flag.
  40. **
  41. ** Version 1.10.2 - 22.6.94
  42. **    Support for -DRGBTXT flag.
  43. **
  44. ** Version 1.10.1 - 21.6.94
  45. **    Different rgb.txt file FreeBSD/386BSD.
  46. **
  47. ** Version 1.10 - 19.6.94
  48. **    Added -g option to change a color in the global color table.
  49. **    Added -B option to change the color for the transparent color index.
  50. **
  51. ** Version 1.9.1 - 7.6.94
  52. **    Different rgb.txt files for X11 and Open Windows.
  53. **
  54. ** Version 1.9 - 1.6.94
  55. **    Fixed a bug which caused color names to be rejected.
  56. **
  57. ** Version 1.8 - 30.5.94
  58. **    Accept #rrggbb style arguments.
  59. **    Do nothing if rgb-color not found in GIF.
  60. **
  61. ** Version 1.7 - 16.5.94
  62. **    Added -l option to only list the color table.
  63. **    Added -L option for verbose output without creating a gif.
  64. **    Added -b option to change the background color index.
  65. **    Display all matching color names for color table entries.
  66. **    Fixed a bug which caused bad color names if rgb.txt starts with
  67. **        whitespace.
  68. **    Doesn't use strdup anymore.
  69. **    Fixed =& bug on dec machines.
  70. **
  71. ** Version 1.6 - 5.4.94
  72. **    Added color names recognition.
  73. **
  74. ** Version 1.5 - 15.3.94
  75. **    Added basic verbose output to analyze GIFs.
  76. **
  77. ** Version 1.4 - 8.3.94
  78. **    Fixed off-by-one bug in Local Color table code.
  79. **    Added -c and -C options to add or remove a comment.
  80. **    Transparency is no longer the default.
  81. **
  82. ** Thanx for bug reports, ideas and fixes to
  83. **    patricka@cs.kun.nl (Patrick Atoon)
  84. **    wes@msc.edu (Wes Barris)
  85. **    pmfitzge@ingr.com (Patrick M. Fitzgerald)
  86. **    hoesel@chem.rug.nl (Frans van Hoesel)
  87. **    boardman@jerry.sal.wisc.edu (Dan Boardman)
  88. **    krweiss@chip.ucdavis.edu (Ken Weiss)
  89. **    chuck.musciano@harris.com (Chuck Musciano)
  90. **    heycke@camis.stanford.edu (Torsten Heycke)
  91. **    claw@spacsun.rice.edu (Colin Law)
  92. **    jwalker@eos.ncsu.edu (Joseph C. Walker)
  93. **    Bjorn.Borud@alkymi.unit.no (Bjorn Borud)
  94. **    Christopher.Vance@adfa.oz.au (CJS Vance)
  95. **    pederl@norway.hp.com (Peder Langlo)
  96. **    I.Rutson@bradford.ac.uk (Ian Rutson)
  97. **    Nicolas.Pioch@enst.fr (Nicolas Pioch)
  98. **    john@charles.CS.UNLV.EDU (John Kilburg)
  99. **    enzo@hk.net (Enzo Michelangeli)
  100. **    twv@hpwtwe0.cup.hp.com (Terry von Gease)
  101. **
  102. ** Original distribution site is
  103. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.c
  104. ** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at
  105. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.1
  106. ** To compile for MS-DOS, you need getopt:
  107. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/getopt.c
  108. ** MS-DOS executable can be found at
  109. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans.exe
  110. ** A template rgb.txt for use with the MS-DOS version can be found at
  111. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/rgb.txt
  112. ** Additional info can be found on
  113. **    http://melmac.corp.harris.com/transparent_images.html
  114. */
  115.  
  116. #define    X11        /* When using X Window System */
  117. #undef    OPENWIN        /* When using Open Windows */
  118. #undef    X386        /* When using FreeBSD/386BSD */
  119. #undef    MSDOS        /* When using Borland C (maybe MSC too) */
  120.  
  121. char header[]="GIFtrans v1.11.1\n(c) 1994 by Andreas Ley\n";
  122.  
  123. #ifndef RGBTXT
  124. #ifdef X11
  125. #define    RGBTXT    "/usr/lib/X11/rgb.txt"
  126. #else /* X11 */
  127. #ifdef OPENWIN
  128. #define    RGBTXT    "/usr/openwin/lib/rgb.txt"
  129. #else /* OPENWIN */
  130. #ifdef X386
  131. #define    RGBTXT    "/usr/X386/lib/X11/rgb.txt"
  132. #else /* X386 */
  133. #ifdef MSDOS
  134. #define    RGBTXT    "rgb.txt"
  135. #else /* MSDOS */
  136. #define    RGBTXT    "";
  137. #endif /* MSDOS */
  138. #endif /* X386 */
  139. #endif /* OPENWIN */
  140. #endif /* X11 */
  141. #endif /* RGBTXT */
  142.  
  143. #include <stdlib.h>
  144. #include <stdio.h>
  145. #include <string.h>
  146. #include <errno.h>
  147. #ifndef MSDOS
  148. #include <unistd.h>
  149. #include <sys/param.h>
  150. #else
  151. #include <fcntl.h>
  152. #include "getopt.c"
  153. #endif
  154.  
  155. #ifndef MAXPATHLEN
  156. #define MAXPATHLEN 256
  157. #endif /* MAXPATHLEN */
  158.  
  159. #define    FALSE    (0)        /* This is the naked Truth */
  160. #define    TRUE    (1)        /* and this is the Light */
  161.  
  162. #define    SUCCESS    (0)
  163. #define    FAILURE    (1)
  164.  
  165. struct entry {
  166.     struct entry    *next;
  167.     char        *name;
  168.     int        red;
  169.     int        green;
  170.     int        blue;
  171.     } *root;
  172.  
  173. #define    NONE    (-1)
  174. #define    OTHER    (-2)
  175. #define    RGB    (-3)
  176.  
  177. struct color {
  178.     int        index;
  179.     int        red;
  180.     int        green;
  181.     int        blue;
  182.     } bc,tc,tn,go,gn;
  183.  
  184. static char    *image,*comment;
  185. static int    skipcomment,list,verbose,output,debug;
  186. static long int    pos;
  187.  
  188. static char    rgb[] = RGBTXT;
  189. static char    true[] = "True";
  190. static char    false[] = "False";
  191.  
  192. #define    readword(buffer)    ((buffer)[0]+256*(buffer)[1])
  193. #define    readflag(buffer)    ((buffer)?true:false)
  194. #define    hex(c)            ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0')
  195.  
  196.  
  197. void dump(adr,data,len)
  198. long int    adr;
  199. unsigned char    *data;
  200. size_t        len;
  201. {
  202.     int    i;
  203.  
  204.     while (len>0) {
  205.         (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),"");
  206.         for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--)
  207.             (void)fprintf(stderr,"%s%02x",i==8?"  ":" ",*data);
  208.         (void)fprintf(stderr,"\n");
  209.     }
  210. }
  211.  
  212.  
  213.  
  214. void writedata(dest,data,len)
  215. FILE        *dest;
  216. unsigned char    *data;
  217. size_t        len;
  218. {
  219.     unsigned char    size;
  220.  
  221.     while (len) {
  222.         size=len<256?len:255;
  223.         (void)fwrite((void *)&size,1,1,dest);
  224.         (void)fwrite((void *)data,(size_t)size,1,dest);
  225.         data+=size;
  226.         len-=size;
  227.     }
  228.     size=0;
  229.     (void)fwrite((void *)&size,1,1,dest);
  230. }
  231.  
  232.  
  233. void skipdata(src)
  234. FILE    *src;
  235. {
  236.     unsigned char    size,buffer[256];
  237.  
  238.     do {
  239.         pos=ftell(src);
  240.         (void)fread((void *)&size,1,1,src);
  241.         if (debug)
  242.             dump(pos,&size,1);
  243.         if (debug) {
  244.             pos=ftell(src);
  245.             (void)fread((void *)buffer,(size_t)size,1,src);
  246.             dump(pos,buffer,(size_t)size);
  247.         }
  248.         else
  249.             (void)fseek(src,(long int)size,SEEK_CUR);
  250.     } while (!feof(src)&&size>0);
  251. }
  252.  
  253.  
  254. void transblock(src,dest)
  255. FILE    *src;
  256. FILE    *dest;
  257. {
  258.     unsigned char    size,buffer[256];
  259.  
  260.     pos=ftell(src);
  261.     (void)fread((void *)&size,1,1,src);
  262.     if (debug)
  263.         dump(pos,&size,1);
  264.     if (output)
  265.         (void)fwrite((void *)&size,1,1,dest);
  266.     pos=ftell(src);
  267.     (void)fread((void *)buffer,(size_t)size,1,src);
  268.     if (debug)
  269.         dump(pos,buffer,(size_t)size);
  270.     if (output)
  271.         (void)fwrite((void *)buffer,(size_t)size,1,dest);
  272. }
  273.  
  274.  
  275. void transdata(src,dest)
  276. FILE    *src;
  277. FILE    *dest;
  278. {
  279.     unsigned char    size,buffer[256];
  280.  
  281.     do {
  282.         pos=ftell(src);
  283.         (void)fread((void *)&size,1,1,src);
  284.         if (debug)
  285.             dump(pos,&size,1);
  286.         if (output)
  287.             (void)fwrite((void *)&size,1,1,dest);
  288.         pos=ftell(src);
  289.         (void)fread((void *)buffer,(size_t)size,1,src);
  290.         if (debug)
  291.             dump(pos,buffer,(size_t)size);
  292.         if (output)
  293.             (void)fwrite((void *)buffer,(size_t)size,1,dest);
  294.     } while (!feof(src)&&size>0);
  295. }
  296.  
  297.  
  298. int giftrans(src,dest)
  299. FILE    *src;
  300. FILE    *dest;
  301. {
  302.     unsigned char    buffer[3*256],lsd[7],gct[3*256],gce[5];
  303.     unsigned int    cnt,cols,size,gct_size,gct_delay,gce_present;
  304.     struct entry    *rgbptr;
  305.  
  306.  
  307.     /* Header */
  308.     pos=ftell(src);
  309.     (void)fread((void *)buffer,6,1,src);
  310.     if (strncmp((char *)buffer,"GIF",3)) {
  311.         (void)fprintf(stderr,"No GIF file!\n");
  312.         return(1);
  313.     }
  314.     if (verbose) {
  315.         buffer[6]='\0';
  316.         (void)fprintf(stderr,"Header: \"%s\"\n",buffer);
  317.     }
  318.     if (debug)
  319.         dump(pos,buffer,6);
  320.     if (output)
  321.         (void)fputs("GIF89a",dest);
  322.  
  323.     /* Logical Screen Descriptor */
  324.     pos=ftell(src);
  325.     (void)fread((void *)lsd,7,1,src);
  326.     if (verbose) {
  327.         (void)fprintf(stderr,"Logical Screen Descriptor:\n");
  328.         (void)fprintf(stderr,"\tLogical Screen Width: %d pixels\n",readword(lsd));
  329.         (void)fprintf(stderr,"\tLogical Screen Height: %d pixels\n",readword(lsd+2));
  330.         (void)fprintf(stderr,"\tGlobal Color Table Flag: %s\n",readflag(lsd[4]&0x80));
  331.         (void)fprintf(stderr,"\tColor Resolution: %d bits\n",(lsd[4]&0x70>>4)+1);
  332.         if (lsd[4]&0x80) {
  333.             (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8));
  334.             (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7));
  335.             (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]);
  336.         }
  337.         if (lsd[6])
  338.             (void)fprintf(stderr,"\tPixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64);
  339.     }
  340.     if (debug)
  341.         dump(pos,lsd,7);
  342.  
  343.     /* Global Color Table */
  344.     gct_delay=FALSE;
  345.     if (lsd[4]&0x80) {
  346.         gct_size=2<<(lsd[4]&0x7);
  347.         pos=ftell(src);
  348.         (void)fread((void *)gct,gct_size,3,src);
  349.         if (go.index==RGB)
  350.             for(cnt=0;cnt<gct_size&&go.index==RGB;cnt++)
  351.                 if (gct[3*cnt]==go.red&&gct[3*cnt+1]==go.green&&gct[3*cnt+2]==go.blue)
  352.                     go.index=cnt;
  353.         if (go.index>=0) {
  354.             if (gn.index>=0) {
  355.                 gn.red=gct[3*gn.index];
  356.                 gn.green=gct[3*gn.index+1];
  357.                 gn.blue=gct[3*gn.index+2];
  358.             }
  359.             gct[3*go.index]=gn.red;
  360.             gct[3*go.index+1]=gn.green;
  361.             gct[3*go.index+2]=gn.blue;
  362.         }
  363.         if (bc.index==RGB)
  364.             for(cnt=0;cnt<gct_size&&bc.index==RGB;cnt++)
  365.                 if (gct[3*cnt]==bc.red&&gct[3*cnt+1]==bc.green&&gct[3*cnt+2]==bc.blue)
  366.                     bc.index=cnt;
  367.         if (bc.index>=0)
  368.             lsd[5]=bc.index;
  369.         if (tc.index==RGB)
  370.             for(cnt=0;cnt<gct_size&&tc.index==RGB;cnt++)
  371.                 if (gct[3*cnt]==tc.red&&gct[3*cnt+1]==tc.green&&gct[3*cnt+2]==tc.blue)
  372.                     tc.index=cnt;
  373.         if (tc.index==OTHER)
  374.             tc.index=lsd[5];
  375.         if (tn.index>=0) {
  376.             tn.red=gct[3*tn.index];
  377.             tn.green=gct[3*tn.index+1];
  378.             tn.blue=gct[3*tn.index+2];
  379.         }
  380.         if (tn.index!=NONE)
  381.             gct_delay=TRUE;
  382.     }
  383.     if (output)
  384.         (void)fwrite((void *)lsd,7,1,dest);
  385.     if (lsd[4]&0x80) {
  386.         if (list||verbose) {
  387.             (void)fprintf(stderr,"Global Color Table:\n");
  388.             for(cnt=0;cnt<gct_size;cnt++) {
  389.                 (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d",cnt,gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  390.                 (void)fprintf(stderr,", #%02x%02x%02x",gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  391.                 for (rgbptr=root,cols=0;rgbptr;rgbptr=rgbptr->next)
  392.                     if (rgbptr->red==gct[3*cnt]&&rgbptr->green==gct[3*cnt+1]&&rgbptr->blue==gct[3*cnt+2])
  393.                         (void)fprintf(stderr,"%s%s",cols++?", ":" (",rgbptr->name);
  394.                 (void)fprintf(stderr,"%s\n",cols?")":"");
  395.             }
  396.         }
  397.         if (debug)
  398.             dump(pos,gct,gct_size*3);
  399.         if (output&&(!gct_delay))
  400.             (void)fwrite((void *)gct,gct_size,3,dest);
  401.     }
  402.  
  403.     gce_present=FALSE;
  404.     do {
  405.         pos=ftell(src);
  406.         (void)fread((void *)buffer,1,1,src);
  407.         switch (buffer[0]) {
  408.         case 0x2c:    /* Image Descriptor */
  409.             if (verbose)
  410.                 (void)fprintf(stderr,"Image Descriptor:\n");
  411.             (void)fread((void *)(buffer+1),9,1,src);
  412.             /* Write Graphic Control Extension */
  413.             if (tc.index>=0||gce_present) {
  414.                 if (!gce_present) {
  415.                     gce[0]=0;
  416.                     gce[1]=0;
  417.                     gce[2]=0;
  418.                 }
  419.                 if (tc.index>=0) {
  420.                     gce[0]|=0x01;    /* Set Transparent Color Flag */
  421.                     gce[3]=tc.index;    /* Set Transparent Color Index */
  422.                 }
  423.                 else if (gce[0]&0x01)
  424.                     tc.index=gce[3];    /* Remember Transparent Color Index */
  425.                 gce[4]=0;
  426.                 if (tc.index>=0&&(!(buffer[8]&0x80))) { /* Transparent Color Flag set and no Local Color Table */
  427.                     gct[3*tc.index]=tn.red;
  428.                     gct[3*tc.index+1]=tn.green;
  429.                     gct[3*tc.index+2]=tn.blue;
  430.                 }
  431.                 if (output&&gct_delay) {
  432.                     (void)fwrite((void *)gct,gct_size,3,dest);
  433.                     gct_delay=FALSE;
  434.                 }
  435.                 if (output) {
  436.                     (void)fputs("\041\371\004",dest);
  437.                     (void)fwrite((void *)gce,5,1,dest);
  438.                 }
  439.             }
  440.             if (output&&gct_delay) {
  441.                 if (verbose)
  442.                     (void)fprintf(stderr,"Warning: Global Color Table has not been modified as no Transparent Color Index has been set\n");
  443.                 (void)fwrite((void *)gct,gct_size,3,dest);
  444.                 gct_delay=FALSE;
  445.             }
  446.             /* Write Image Descriptor */
  447.             if (verbose) {
  448.                 (void)fprintf(stderr,"\tImage Left Position: %d pixels\n",readword(buffer+1));
  449.                 (void)fprintf(stderr,"\tImage Top Position: %d pixels\n",readword(buffer+3));
  450.                 (void)fprintf(stderr,"\tImage Width: %d pixels\n",readword(buffer+5));
  451.                 (void)fprintf(stderr,"\tImage Height: %d pixels\n",readword(buffer+7));
  452.                 (void)fprintf(stderr,"\tLocal Color Table Flag: %s\n",readflag(buffer[9]&0x80));
  453.                 (void)fprintf(stderr,"\tInterlace Flag: %s\n",readflag(buffer[9]&0x40));
  454.                 if (buffer[9]&0x80) {
  455.                     (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(buffer[9]&0x20));
  456.                     (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(buffer[9]&0x7));
  457.                 }
  458.             }
  459.             if (debug)
  460.                 dump(pos,buffer,10);
  461.             if (output)
  462.                 (void)fwrite((void *)buffer,10,1,dest);
  463.             /* Local Color Table */
  464.             if (buffer[8]&0x80) {
  465.                 size=2<<(buffer[8]&0x7);
  466.                 pos=ftell(src);
  467.                 (void)fread((void *)buffer,size,3,src);
  468.                 if (verbose) {
  469.                     (void)fprintf(stderr,"Local Color Table:\n");
  470.                     for(cnt=0;cnt<size;cnt++)
  471.                         (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d\n",cnt,buffer[3*cnt],buffer[3*cnt+1],buffer[3*cnt+2]);
  472.                 }
  473.                 if (tc.index>=0) { /* Transparent Color Flag set */
  474.                     buffer[3*tc.index]=tn.red;
  475.                     buffer[3*tc.index+1]=tn.green;
  476.                     buffer[3*tc.index+2]=tn.blue;
  477.                 }
  478.                 if (debug)
  479.                     dump(pos,buffer,size*3);
  480.                 if (output)
  481.                     (void)fwrite((void *)buffer,size,3,dest);
  482.             }
  483.             /* Table Based Image Data */
  484.             pos=ftell(src);
  485.             (void)fread((void *)buffer,1,1,src);
  486.             if (verbose) {
  487.                 (void)fprintf(stderr,"Table Based Image Data:\n");
  488.                 (void)fprintf(stderr,"\tLZW Minimum Code Size: 0x%02x\n",buffer[0]);
  489.             }
  490.             if (debug)
  491.                 dump(pos,buffer,1);
  492.             if (output)
  493.                 (void)fwrite((void *)buffer,1,1,dest);
  494.             transdata(src,dest);
  495.             gce_present=FALSE;
  496.             break;
  497.         case 0x3b:    /* Trailer */
  498.             if (verbose)
  499.                 (void)fprintf(stderr,"Trailer\n");
  500.             if (debug)
  501.                 dump(pos,buffer,1);
  502.             if (comment&&*comment&&output) {
  503.                 (void)fputs("\041\376",dest);
  504.                 writedata(dest,(unsigned char *)comment,strlen(comment));
  505.             }
  506.             if (output)
  507.                 (void)fwrite((void *)buffer,1,1,dest);
  508.             break;
  509.         case 0x21:    /* Extension */
  510.             (void)fread((void *)(buffer+1),1,1,src);
  511.             switch (buffer[1]) {
  512.             case 0x01:    /* Plain Text Extension */
  513.                 if (output&&gct_delay) {
  514.                     if (verbose)
  515.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Plain Text Extension\n");
  516.                     (void)fwrite((void *)gct,gct_size,3,dest);
  517.                     gct_delay=FALSE;
  518.                 }
  519.                 if (verbose)
  520.                     (void)fprintf(stderr,"Plain Text Extension\n");
  521.                 if (debug)
  522.                     dump(pos,buffer,2);
  523.                 if (output)
  524.                     (void)fwrite((void *)buffer,2,1,dest);
  525.                 transblock(src,dest);
  526.                 transdata(src,dest);
  527.                 break;
  528.             case 0xf9:    /* Graphic Control Extension */
  529.                 if (verbose)
  530.                     (void)fprintf(stderr,"Graphic Control Extension:\n");
  531.                 (void)fread((void *)(buffer+2),1,1,src);
  532.                 size=buffer[2];
  533.                 (void)fread((void *)gce,size,1,src);
  534.                 if (verbose) {
  535.                     (void)fprintf(stderr,"\tDisposal Method: %d ",gce[0]&0x1c>>2);
  536.                     switch (gce[0]&0x1c>>2) {
  537.                     case 0:
  538.                         (void)fprintf(stderr,"(no disposal specified)\n");
  539.                         break;
  540.                     case 1:
  541.                         (void)fprintf(stderr,"(do not dispose)\n");
  542.                         break;
  543.                     case 2:
  544.                         (void)fprintf(stderr,"(restore to background color)\n");
  545.                         break;
  546.                     case 3:
  547.                         (void)fprintf(stderr,"(restore to previous)\n");
  548.                         break;
  549.                     default:
  550.                         (void)fprintf(stderr,"(to be defined)\n");
  551.                     }
  552.                     (void)fprintf(stderr,"\tUser Input Flag: %s\n",readflag(gce[0]&0x2));
  553.                     (void)fprintf(stderr,"\tTransparent Color Flag: %s\n",readflag(gce[0]&0x1));
  554.                     (void)fprintf(stderr,"\tDelay Time: %d\n",readword(gce+1));
  555.                     if (gce[0]&0x1)
  556.                         (void)fprintf(stderr,"\tTransparent Color Index: %d\n",gce[3]);
  557.                 }
  558.                 if (debug) {
  559.                     dump(pos,buffer,3);
  560.                     dump(pos+3,gce,size);
  561.                 }
  562.                 pos=ftell(src);
  563.                 (void)fread((void *)buffer,1,1,src);
  564.                 if (debug)
  565.                     dump(pos,buffer,1);
  566.                 gce_present=TRUE;
  567.                 break;
  568.             case 0xfe:    /* Comment Extension */
  569.                 if (verbose)
  570.                     (void)fprintf(stderr,"Comment Extension\n");
  571.                 if (debug)
  572.                     dump(pos,buffer,2);
  573.                 if (skipcomment)
  574.                     skipdata(src);
  575.                 else {
  576.                     if (output&&gct_delay) {
  577.                         if (verbose)
  578.                             (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Comment Extension\n");
  579.                         (void)fwrite((void *)gct,gct_size,3,dest);
  580.                         gct_delay=FALSE;
  581.                     }
  582.                     if (output)
  583.                         (void)fwrite((void *)buffer,2,1,dest);
  584.                     transdata(src,dest);
  585.                 }
  586.                 break;
  587.             case 0xff:    /* Application Extension */
  588.                 if (output&&gct_delay) {
  589.                     if (verbose)
  590.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Application Extension\n");
  591.                     (void)fwrite((void *)gct,gct_size,3,dest);
  592.                     gct_delay=FALSE;
  593.                 }
  594.                 if (verbose)
  595.                     (void)fprintf(stderr,"Application Extension\n");
  596.                 if (debug)
  597.                     dump(pos,buffer,2);
  598.                 if (output)
  599.                     (void)fwrite((void *)buffer,2,1,dest);
  600.                 transblock(src,dest);
  601.                 transdata(src,dest);
  602.                 break;
  603.             default:
  604.                 if (output&&gct_delay) {
  605.                     if (verbose)
  606.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to an unknown Extension\n");
  607.                     (void)fwrite((void *)gct,gct_size,3,dest);
  608.                     gct_delay=FALSE;
  609.                 }
  610.                 if (verbose)
  611.                     (void)fprintf(stderr,"Unknown label: 0x%02x\n",buffer[1]);
  612.                 if (debug)
  613.                     dump(pos,buffer,2);
  614.                 if (output)
  615.                     (void)fwrite((void *)buffer,2,1,dest);
  616.                 transblock(src,dest);
  617.                 transdata(src,dest);
  618.                 break;
  619.             }
  620.             break;
  621.         default:
  622.             (void)fprintf(stderr,"0x%08lx: Unknown extension 0x%02x!\n",ftell(src)-1,buffer[0]);
  623.             if (debug)
  624.                 dump(pos,buffer,1);
  625.             return(1);
  626.         }
  627.     } while (buffer[0]!=0x3b&&!feof(src));
  628.     return(buffer[0]==0x3b?SUCCESS:FAILURE);
  629. }
  630.  
  631.  
  632.  
  633. int getindex(c,arg)
  634. struct color    *c;
  635. char    *arg;
  636. {
  637.     struct entry    *ptr;
  638.  
  639.     if ('0'<=*arg&&*arg<='9')
  640.         c->index=atoi(arg);
  641.     else if (*arg=='#') {
  642.         if (strlen(arg)==4) {
  643.             c->index=RGB;
  644.             c->red=hex(arg[1])<<4;
  645.             c->green=hex(arg[2])<<4;
  646.             c->blue=hex(arg[3])<<4;
  647.         }
  648.         else if (strlen(arg)==7) {
  649.             c->index=RGB;
  650.             c->red=(hex(arg[1])<<4)+hex(arg[2]);
  651.             c->green=(hex(arg[3])<<4)+hex(arg[4]);
  652.             c->blue=(hex(arg[5])<<4)+hex(arg[6]);
  653.         }
  654.         else {
  655.             (void)fprintf(stderr,"%s: illegal color specification: %s\n",image,arg);
  656.             return(FAILURE);
  657.         }
  658.     }
  659.     else {
  660.         for (ptr=root;ptr&&c->index!=RGB;ptr=ptr->next)
  661.             if (!strcmp(ptr->name,arg)) {
  662.                 c->index=RGB;
  663.                 c->red=ptr->red;
  664.                 c->green=ptr->green;
  665.                 c->blue=ptr->blue;
  666.             }
  667.         if (c->index!=RGB) {
  668.             (void)fprintf(stderr,"%s: no such color: %s\n",image,arg);
  669.             return(FAILURE);
  670.         }
  671.     }
  672.     return(SUCCESS);
  673. }
  674.  
  675.  
  676.  
  677. void usage()
  678. {
  679.     (void)fprintf(stderr,"Usage: %s [-t color|-T] [-B color] [-b color] [-g oldcolor=newcolor] [-c comment|-C] [-l|-L|-V] [-o filename] [-e filename] [filename]\n",image);
  680.     (void)fprintf(stderr,"Convert any GIF file into a GIF89a, with the folloing changes possible:\n");
  681.     (void)fprintf(stderr,"-t Specify the transparent color\n");
  682.     (void)fprintf(stderr,"-T Index of the transparent color is the background color index\n");
  683.     (void)fprintf(stderr,"-B Specify the transparent color's new value\n");
  684.     (void)fprintf(stderr,"-b Specify the background color\n");
  685.     (void)fprintf(stderr,"-g Change a color in the global color table\n");
  686.     (void)fprintf(stderr,"-c Add a comment\n");
  687.     (void)fprintf(stderr,"-C Remove old comment\n");
  688.     (void)fprintf(stderr,"-l Only list the color table\n");
  689.     (void)fprintf(stderr,"-L Verbose output of GIFs contents\n");
  690.     (void)fprintf(stderr,"-V Verbose output while converting\n");
  691.     (void)fprintf(stderr,"-o Redirect stdout to a file\n");
  692.     (void)fprintf(stderr,"-e Redirect stderr to a file\n");
  693.     if (*rgb)
  694.         (void)fprintf(stderr,"Colors may be specified as index, as rgb.txt entry or in the #rrggbb form.\n");
  695.     else
  696.         (void)fprintf(stderr,"Colors may be specified as index or in the #rrggbb form.\n");
  697.     exit(1);
  698. }
  699.  
  700.  
  701. int main(argc,argv)
  702. int    argc;
  703. char    *argv[];
  704. {
  705.     int        c;
  706.     extern char    *optarg;
  707.     extern int    optind;
  708.     char        error[2*MAXPATHLEN+14],line[BUFSIZ],*ptr,*nptr,*oname,*ename;
  709.     struct entry    **next;
  710.     FILE        *src;
  711.     int        stat;
  712.  
  713.     image=argv[0];
  714.     root=NULL;
  715.     if (*rgb)
  716.         if ((src=fopen(rgb,"r"))!=NULL) {
  717.             next= &root;
  718.             while (fgets(line,sizeof(line),src)) {
  719.                 *next=(struct entry *)malloc(sizeof(struct entry));
  720.                 for (ptr=line;strchr(" \t",*ptr);ptr++);
  721.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  722.                 *ptr++='\0';
  723.                 (*next)->red=atoi(nptr);
  724.                 for (;strchr(" \t",*ptr);ptr++);
  725.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  726.                 *ptr++='\0';
  727.                 (*next)->green=atoi(nptr);
  728.                 for (;strchr(" \t",*ptr);ptr++);
  729.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  730.                 *ptr++='\0';
  731.                 (*next)->blue=atoi(nptr);
  732.                 for (;strchr(" \t",*ptr);ptr++);
  733.                 for (nptr=ptr;!strchr(" \t\r\n",*ptr);ptr++);
  734.                 *ptr='\0';
  735.                 (void)strcpy((*next)->name=(char *)malloc(strlen(nptr)+1),nptr);
  736.                 (*next)->next=NULL;
  737.                 next= &(*next)->next;
  738.             }
  739.             (void)fclose(src);
  740.         }
  741.         else {
  742. #ifndef MSDOS
  743.             (void)sprintf(error,"%s: cannot open %s",image,rgb);
  744.             perror(error);
  745.             return(FAILURE);
  746. #else /* MSDOS */
  747.             *rgb='\0';
  748. #endif
  749.         }
  750.  
  751.     bc.index=NONE;
  752.     tc.index=NONE;
  753.     tn.index=NONE;
  754.     go.index=NONE;
  755.     gn.index=NONE;
  756.     comment=NULL;
  757.     skipcomment=FALSE;
  758.     verbose=FALSE;
  759.     output=TRUE;
  760.     debug=FALSE;
  761.     oname=NULL;
  762.     ename=NULL;
  763.     while ((c=getopt(argc,argv,"t:TB:b:g:c:ClLVDo:e:vh?")) != EOF)
  764.         switch ((char)c) {
  765.         case 'b':
  766.             if (getindex(&bc,optarg))
  767.                 return(FAILURE);
  768.             break;
  769.         case 't':
  770.             if (getindex(&tc,optarg))
  771.                 return(FAILURE);
  772.             break;
  773.         case 'T':
  774.             tc.index=OTHER;
  775.             break;
  776.         case 'B':
  777.             if (getindex(&tn,optarg))
  778.                 return(FAILURE);
  779.             break;
  780.         case 'g':
  781.             if ((ptr=strchr(optarg,'='))!=NULL) {
  782.                 *ptr++='\0';
  783.                 if (getindex(&go,optarg))
  784.                     return(FAILURE);
  785.                 if (getindex(&gn,ptr))
  786.                     return(FAILURE);
  787.             }
  788.             else
  789.                 usage();
  790.             break;
  791.         case 'c':
  792.             comment=optarg;
  793.             break;
  794.         case 'C':
  795.             skipcomment=TRUE;
  796.             break;
  797.         case 'l':
  798.             list=TRUE;
  799.             output=FALSE;
  800.             break;
  801.         case 'L':
  802.             verbose=TRUE;
  803.             output=FALSE;
  804.             break;
  805.         case 'V':
  806.             verbose=TRUE;
  807.             break;
  808.         case 'D':
  809.             debug=TRUE;
  810.             break;
  811.         case 'o':
  812.             oname=optarg;
  813.             break;
  814.         case 'e':
  815.             ename=optarg;
  816.             break;
  817.         case 'v':
  818.             (void)fprintf(stderr,header);
  819.             return(0);
  820.         case 'h':
  821.             (void)fprintf(stderr,header);
  822.         case '?':
  823.             usage();
  824.         }
  825.     if (optind+1<argc||(bc.index==NONE&&tc.index==NONE&&tn.index==NONE&&gn.index==NONE&&comment==NULL&&!skipcomment&&!list&&!verbose))
  826.         usage();
  827.  
  828.     if (oname&&freopen(oname,"wb",stdout)==NULL) {
  829.         (void)sprintf(error,"%s: cannot open %s",image,oname);
  830.         perror(error);
  831.         return(FAILURE);
  832.     }
  833.  
  834.     if (ename&&freopen(ename,"wb",stderr)==NULL) {
  835.         (void)sprintf(error,"%s: cannot open %s",image,ename);
  836.         perror(error);
  837.         return(FAILURE);
  838.     }
  839.  
  840. #ifdef MSDOS
  841.     if(oname==NULL&&(stdout->flags&_F_TERM)==0&&setmode(fileno(stdout),O_BINARY)!=0) {
  842.         (void)fprintf(stderr,"%s: can't set stdout's mode to binary\n",image);
  843.         exit(2);
  844.     }
  845.     if(optind==argc&&(stdin->flags&_F_TERM)==0&&setmode(fileno(stdin),O_BINARY)) {
  846.         (void)fprintf(stderr,"%s: can't set stdin's mode to binary\n",image);
  847.         exit(2);
  848.     }
  849. #endif /* MSDOS */
  850.  
  851.     if (optind<argc)
  852.         if (strcmp(argv[optind],"-"))
  853.             if ((src=fopen(argv[optind],"rb"))!=NULL) {
  854.                 stat=giftrans(src,stdout);
  855.                 (void)fclose(src);
  856.             }
  857.             else {
  858.                 (void)sprintf(error,"%s: cannot open %s",image,argv[optind]);
  859.                 perror(error);
  860.                 return(FAILURE);
  861.             }
  862.         else
  863.             stat=giftrans(stdin,stdout);
  864.     else
  865.         stat=giftrans(stdin,stdout);
  866.  
  867.     (void)fclose(stdout);
  868.     (void)fclose(stderr);
  869.     return(stat);
  870. }
  871.